<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
    1. 创建画布元素
    2. 获取画笔
    3.获取列的数量

    -->
    <style>
        /* 设置画布样式，背景为黑色，覆盖整个视口 */
        canvas {
            background: black;
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
        }
    </style>
</head>

<body>
    <!-- 创建canvas元素用于绘制代码雨效果 -->
    <canvas id="canvas"></canvas>

    <script>
        // 获取画布元素
        const cvs = document.getElementById('canvas');

        // 获取窗口尺寸，考虑设备像素比以获得更清晰的显示效果
        const width = window.innerWidth * devicePixelRatio;
        const height = window.innerHeight * devicePixelRatio;

        // 设置画布尺寸
        cvs.width = width;
        cvs.height = height;

        // 获取2D绘图上下文
        const ctx = cvs.getContext('2d');

        // 字体大小，考虑设备像素比
        const fontSize = 20 * devicePixelRatio;

        // 设置列的大小
        const columns = fontSize;

        // 计算列的数量
        const columnCount = Math.floor(canvas.width / columns);
        // 每一列下一个文字y坐标，初始化为0
        const nextChars = new Array(columnCount).fill(0);

        // 绘制代码雨效果的主要函数
        function draw() {
            // 绘制半透明黑色矩形作为背景，创建拖尾效果
            ctx.fillStyle = 'rgba(0,0,0,0.1)';
            ctx.fillRect(0, 0, width, height);
            
            // 遍历每一列
            for (let i = 0; i < columnCount; i++) {
                // 获取随机字符
                const char = getRandomChar();
                // 获取随机颜色
                const color = getRandomColor();
                // 计算当前列的x坐标
                const x = i * columns;

                // 设置文本基线
                ctx.textBaseline = 'top';
                // 计算当前字符的y坐标
                const y = fontSize * nextChars[i];
                // 设置填充颜色
                ctx.fillStyle = color;
                // 设置字体大小和字体
                ctx.font = `${fontSize}px "Roboto Mono"`;
                // 在指定位置绘制字符
                ctx.fillText(char, x, y);

                // 如果字符超出画布高度且满足随机条件，则重置该列
                if (y > canvas.height && Math.random() > 0.9) {
                    nextChars[i] = 0;
                } else {
                    // 否则继续向下移动
                    nextChars[i]++;
                }
            }
        }

        // 获取随机颜色的函数
        function getRandomColor() {
            // 定义颜色数组
            const fontColor = [
                '#33B5E5',
                '#0099CC',
                '#AA66CC',
                '#9933CC',
                '#99CC00',
                '#669900',
                '#FFBB33',
                '#FF8800',
                '#FF4444',
                '#CC0000'
            ];
            // 随机返回一个颜色
            return fontColor[Math.floor(Math.random() * fontColor.length)];
        };

        // 获取随机字符的函数
        function getRandomChar() {
            // 定义字符集
            const char = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
            // 随机返回一个字符
            return char[Math.floor(Math.random() * char.length)];
        };

        // 立即执行一次绘制
        draw();
        // 每50毫秒执行一次绘制，形成动画效果
        setInterval(() => {
            draw();
        }, 50)
    </script>
</body>

</html>